package com.songcan.oauth.handle;

import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.songcan.common.contans.CacheAuthContans;
import com.songcan.common.exception.AuthException;
import com.songcan.common.vo.CoreResult;
import com.songcan.common.vo.UserDetailsNew;
import com.songcan.oauth.client.ClientService;
import com.songcan.oauth.confinguration.ThreeTokenGranter;
import com.songcan.oauth.other.CoreLoginAuthenticationToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import static com.songcan.common.contans.CoreContants.*;

@Slf4j
@Configuration
public class CoreLoginSuccessHandler implements AuthenticationSuccessHandler {

    public static final String BASIC_ = "Basic ";

    final Base64.Decoder decoder = Base64.getDecoder();


    private ClientService clientService;
    private RedisTemplate redisTemplate;




    @Autowired
    public CoreLoginSuccessHandler(ClientService clientService,
                                   RedisTemplate redisTemplate){
        this.clientService = clientService;
        this.redisTemplate = redisTemplate;

    }




    /**
     * Called when a user has been successfully authenticated.
     * 调用spring security oauth API 生成 oAuth2AccessToken
     *
     * @param request        the request which caused the successful authentication
     * @param response       the response
     * @param authentication the <tt>Authentication</tt> object which was created during
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        String header = request.getHeader(TOKEN_KEY);
        response.setCharacterEncoding(UTF8);
        response.setContentType(CONTENT_TYPE);
        CoreLoginAuthenticationToken authenticationToken = (CoreLoginAuthenticationToken) authentication;

        if (authenticationToken.getType() != null && authenticationToken.getType().equalsIgnoreCase("qrcode")) {
            String client = request.getHeader("client");
            if (client == null || !client.startsWith(BASIC_)) {
                throw new UnapprovedClientAuthenticationException("请求头中client信息为空");
            }
            header = client;
        } else {
            if (header == null || !header.startsWith(BASIC_)) {
                throw new UnapprovedClientAuthenticationException("请求头中client信息为空");
            }
        }

        try {
            PrintWriter printWriter = response.getWriter();
            if (header.contains(BASIC_)) {
                header = header.replace(BASIC_, "");
                header = new String(decoder.decode(header), "UTF-8");
            }
            //头部信息解码
            String[] tokens = header.split(":");
            assert tokens.length == 2;
            String clientId = tokens[0];

            ClientDetails clientDetails = clientService.loadClientByClientId(clientId);

            //校验secret
            if (!clientDetails.getClientSecret().equals(tokens[1])) {
                throw new InvalidClientException("Given client ID does not match authenticated client");
            }
            Map<String,String[]> map = request.getParameterMap();
            Map<String,String> requestParam = new HashMap<>();
            for (String s : map.keySet()) {
                 String[] parm = map.get(s);
                 requestParam.put(s,parm[0]);
            }
            TokenRequest tokenRequest = new TokenRequest(requestParam, clientId, clientDetails.getScope(), authenticationToken.getType());
            //校验scope
            new DefaultOAuth2RequestValidator().validateScope(tokenRequest, clientDetails);

            OAuth2AccessToken accessToken =initGranter(authenticationToken.getType()).grant(authenticationToken.getType(),tokenRequest); //.createAccessToken(oAuth2Authentication);
            log.info("获取token 成功：{}", accessToken.getValue());

            DefaultOAuth2AccessToken oAuth2AccessToken = new DefaultOAuth2AccessToken(accessToken);
            //判断是否二维码登录

            if (authenticationToken.getType() == null) {
                throw new AuthException("认证异常，Type不能为空");
            }
            JSONObject jsonObject = new JSONObject();
              if(authenticationToken.getType().equals(TYPE_WECHAT)) {
                  jsonObject.put("access_token", oAuth2AccessToken.getValue());
                  jsonObject.put("token_type", oAuth2AccessToken.getTokenType());
                  jsonObject.put("expires_in", oAuth2AccessToken.getExpiresIn());
                  jsonObject.put("license", oAuth2AccessToken.getAdditionalInformation().get("license"));
                  jsonObject.put("refresh_token", oAuth2AccessToken.getRefreshToken().getValue());
                  jsonObject.put("union_id", UserDetailsNew.class.cast(authenticationToken.getPrincipal()).getUsername());
                  jsonObject.put("bind_mobile",authenticationToken.getBindMobile());
              }else{
                  jsonObject.put("access_token", oAuth2AccessToken.getValue());
                  jsonObject.put("token_type", oAuth2AccessToken.getTokenType());
                  jsonObject.put("expires_in", oAuth2AccessToken.getExpiresIn());
                  jsonObject.put("license", oAuth2AccessToken.getAdditionalInformation().get("license"));
                  jsonObject.put("refresh_token", oAuth2AccessToken.getRefreshToken().getValue());
              }
            printWriter.append(JSON.toJSONString(new CoreResult(jsonObject)));
        } catch (IOException e) {
            response.setStatus(HttpStatus.HTTP_OK);
        }
    }




    private ThreeTokenGranter initGranter(String grantType){
        RedisTokenStore yfRedisTokenStore = new RedisTokenStore(redisTemplate.getConnectionFactory());
        DefaultOAuth2RequestFactory requestFactory = new DefaultOAuth2RequestFactory(clientService);
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setReuseRefreshToken(true);
        defaultTokenServices.setTokenStore(yfRedisTokenStore);
        ThreeTokenGranter threeTokenGranter = new ThreeTokenGranter(grantType,defaultTokenServices,clientService,requestFactory);
        return  threeTokenGranter;
    }



}
